package cs.threephase;

import static cs.threephase.Util.*;
import static cs.threephase.Moves.*;

import java.util.*;

//import android.os.Handler;

class Center2 {

	byte[] rl = new byte[8];
	int[] ct = new int[16];
	int parity = 0;
	
	static int[][] rlmv = new int[70][28];
	static char[][] ctmv = new char[6435][28];
	static char[][] rlrot = new char[70][16];
	static char[][] ctrot = new char[6435][16];
	static byte[] ctprun = new byte[6435*35*2];
	
	private static int[] pmv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 
						0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0};
		
	public static void initRl() {
		Center2 c = new Center2();
		for (int i=0; i<35*2; i++) {
			for (int m=0; m<28; m++) {
				c.setrl(i);
				c.move(move2std[m]);
				rlmv[i][m] = c.getrl();
			}
		}
		for (int i=0; i<70; i++) {
			c.setrl(i);
			for (int j=0; j<16; j++) {
				rlrot[i][j] = (char) c.getrl();
				c.rot(0);
				if ((j&1)==1) c.rot(1);
				if ((j&7)==7) c.rot(2);
			}
		}
	}
	
	public static void initCt() {
		Center2 c = new Center2();
		for (int i=0; i<6435; i++) {
			c.setct(i);
			for (int j=0; j<16; j++) {
				ctrot[i][j] = (char) c.getct();
				c.rot(0);
				if ((j&1)==1) c.rot(1);
				if ((j&7)==7) c.rot(2);
			}
		}
		for (int i=0; i<6435; i++) {
			for (int m=0; m<28; m++) {
				c.setct(i);
				c.move(move2std[m]);
				ctmv[i][m] = (char)c.getct();
			}
		}
		Arrays.fill(ctprun, (byte)-1);
		ctprun[0] = ctprun[18] = ctprun[28] = ctprun[46] = ctprun[54] = ctprun[56] = 0;
		int depth = 0;
		int done = 6;
		while (done != 6435*35*2) {
			for (int i=0; i<6435*35*2; i++) {
				if (ctprun[i]==depth) {
					int ct = i / 70;
					int rl = i % 70;
					for (int m=0; m<23; m++) {
						int ctx = ctmv[ct][m];
						int rlx = rlmv[rl][m];
						int idx = ctx * 70 + rlx;
						if (ctprun[idx] == -1) {
							ctprun[idx] = (byte)(depth+1);
							done++;
						}
					}
				}
			}
			depth++;
//			System.out.println(String.format("%2d%10d", depth, done));
		}
	}
	
	Center2() {
	
	}
	
	Center2(CenterCube c) {
		this();
		for (int i=0; i<16; i++) {
			ct[i] = c.ct[i] >> 1;
		}
		System.arraycopy(c.ct, 16, rl, 0, 8);
	}
	
	void set(CenterCube c, int edgeParity) {
		for (int i=0; i<16; i++) {
			ct[i] = c.ct[i] >> 1;
		}
		System.arraycopy(c.ct, 16, rl, 0, 8);
		parity = edgeParity;
	}

	int getrl() {
		int idx = 0;
		int r = 4;
		for (int i=6; i>=0; i--) {
			if (rl[i] != rl[7]) {
				idx += Cnk[i][r--];
			}
		}
		return idx * 2 + parity;
	}
	
	void setrl(int idx) {
		parity = idx & 1;
		idx >>>= 1;
		int r = 4;
		rl[7] = 0;
		for (int i=6; i>=0; i--) {
			if (idx >= Cnk[i][r]) {
				idx -= Cnk[i][r--];
				rl[i] = 1;
			} else {
				rl[i] = 0;
			}
		}
	}

	int getct() {
		int idx = 0;
		int r = 8;
		for (int i=14; i>=0; i--) {
			if (ct[i] != ct[15]) {
				idx += Cnk[i][r--];
			}
		}
		return idx;
	}
	
	void setct(int idx) {
		int r = 8;
		ct[15] = 0;
		for (int i=14; i>=0; i--) {
			if (idx >= Cnk[i][r]) {
				idx -= Cnk[i][r--];
				ct[i] = 1;
			} else {
				ct[i] = 0;
			}
		}
	}	
	
	void rot(int r) {
		switch (r) {
			case 0:
				move(ux2);
				move(dx2);
				break;
			case 1:
				move(rx1);
				move(lx3);
				break;
			case 2:
				swap(ct, 0, 3, 1, 2, 1);
				swap(ct, 8, 11, 9, 10, 1);
				swap(ct, 4, 7, 5, 6, 1);
				swap(ct, 12, 15, 13, 14, 1);
				swap(rl, 0, 3, 5, 6, 1);
				swap(rl, 1, 2, 4, 7, 1);
				break;
		}	
	}

	
	void move(int m) {
		parity ^= pmv[m];
		int key = m % 3;
		m /= 3;
		switch (m) {
			case 0:		//U
				swap(ct, 0, 1, 2, 3, key);
				break;
			case 1:		//R
				swap(rl, 0, 1, 2, 3, key);
				break;
			case 2:		//F
				swap(ct, 8, 9, 10, 11, key);
				break;
			case 3:		//D
				swap(ct, 4, 5, 6, 7, key);
				break;
			case 4:		//L
				swap(rl, 4, 5, 6, 7, key);
				break;
			case 5:		//B
				swap(ct, 12, 13, 14, 15, key);
				break;
			case 6:		//u
				swap(ct, 0, 1, 2, 3, key);
				swap(rl, 0, 5, 4, 1, key);
				swap(ct, 8, 9, 12, 13, key);
				break;
			case 7:		//r
				swap(rl, 0, 1, 2, 3, key);
				swap(ct, 1, 15, 5, 9, key);
				swap(ct, 2, 12, 6, 10, key);
				break;
			case 8:		//f
				swap(ct, 8, 9, 10, 11, key);
				swap(rl, 0, 3, 6, 5, key);
				swap(ct, 3, 2, 5, 4, key);
				break;
			case 9:		//d
				swap(ct, 4, 5, 6, 7, key);
				swap(rl, 3, 2, 7, 6, key);
				swap(ct, 11, 10, 15, 14, key);
				break;
			case 10:	//l
				swap(rl, 4, 5, 6, 7, key);
				swap(ct, 0, 8, 4, 14, key);
				swap(ct, 3, 11, 7, 13, key);
				break;
			case 11:	//b		
				swap(ct, 12, 13, 14, 15, key);
				swap(rl, 1, 4, 7, 2, key);
				swap(ct, 1, 0, 7, 6, key);
				break;
		}
	}
}
